package com.time.client.domain.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.time.client.common.entity.PageResult;
import com.time.client.common.enums.CommentStatusEnum;
import com.time.client.common.enums.CommentTypeEnum;
import com.time.client.common.enums.IsDeletedFlagEnum;
import com.time.client.domain.converter.CommentBOConverter;
import com.time.client.domain.entity.CommentBO;
import com.time.client.domain.redis.RedisUtil;
import com.time.client.domain.service.ClientCommentDomainService;
import com.time.client.infra.basic.entity.Comment;
import com.time.client.infra.basic.service.CommentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 评论管理领域服务层接口实现类
 *
 * @author: HuangQi
 * @date: Created in 10:48 2025/11/3
 * @description: 评论管理领域服务层接口实现类
 */
@Slf4j
@Service("clientCommentDomainService")
public class ClientCommentDomainServiceImpl implements ClientCommentDomainService {

    @Autowired
    private CommentService commentService;
    @Autowired
    private RedisUtil redisUtil;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final long COMMENT_CACHE_TIMEOUT_MINUTES = 5L;
    private static final long COMMENT_CACHE_JITTER_MINUTES = 3L;
    private static final TimeUnit COMMENT_CACHE_TIMEUNIT = TimeUnit.MINUTES;

    @Override
    public Boolean add(CommentBO commentBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientCommentDomainServiceImpl.add.bo:{}", commentBO);
        }

        // 参数转换
        Comment comment = CommentBOConverter.INSTANCE.convertBOToEntity(commentBO);
        comment.setType(comment.getPostId() == null ? CommentTypeEnum.MESSAGE_COMMENT.getCode() : CommentTypeEnum.POST_COMMENT.getCode());
        comment.setStatus(CommentStatusEnum.PENDING.getCode());
        comment.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 调用 service
        int count = commentService.insert(comment);

        return count > 0;
    }

    @Override
    public PageResult<CommentBO> queryPageComment(CommentBO commentBO) {
        if (log.isInfoEnabled()) {
            log.info("ClientCommentDomainServiceImpl.queryPageComment.bo:{}", commentBO);
        }

        String cacheKey = redisUtil.buildKey("client", "comment", "queryAll", serializeKey(commentBO));
        PageResult<CommentBO> cacheResult = getCache(cacheKey, new TypeReference<PageResult<CommentBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 参数转换
        Comment comment = CommentBOConverter.INSTANCE.convertBOToEntity(commentBO);
        comment.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 创建分页结果
        PageResult<CommentBO> pageResult = new PageResult<>();
        pageResult.setPageNo(commentBO.getPageNo());
        pageResult.setPageSize(commentBO.getPageSize());

        // 获取总记录数
        int total = commentService.count(comment);
        pageResult.setTotal(total);

        // 获取分页的评论信息（使用PageResult自动计算的start）
        int start = (pageResult.getStart() - 1); // PageResult的start是从1开始的，需要转换为从0开始
        List<Comment> commentList = commentService.queryPageByCondition(comment, start, pageResult.getPageSize());

        // 参数转换
        List<CommentBO> commentBOList = CommentBOConverter.INSTANCE.convertEntityListToBO(commentList);

        // 设置分页结果
        pageResult.setResult(commentBOList);

        setCache(cacheKey, pageResult);
        // 返回结果
        return pageResult;
    }

    private <T> T getCache(String key, TypeReference<T> typeReference) {
        try {
            String cacheValue = redisUtil.get(key);
            if (cacheValue == null) {
                return null;
            }
            return OBJECT_MAPPER.readValue(cacheValue,
                    OBJECT_MAPPER.getTypeFactory().constructType(typeReference.getType()));
        } catch (Exception e) {
            log.warn("ClientCommentDomainServiceImpl.getCache.error:key={}, msg={}", key, e.getMessage());
            return null;
        }
    }

    private void setCache(String key, Object value) {
        try {
            long ttl = COMMENT_CACHE_TIMEOUT_MINUTES +
                    ThreadLocalRandom.current().nextLong(COMMENT_CACHE_JITTER_MINUTES + 1);
            redisUtil.set(key, OBJECT_MAPPER.writeValueAsString(value), ttl, COMMENT_CACHE_TIMEUNIT);
        } catch (Exception e) {
            log.warn("ClientCommentDomainServiceImpl.setCache.error:key={}, msg={}", key, e.getMessage());
        }
    }

    private String serializeKey(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("ClientCommentDomainServiceImpl.serializeKey.error:{}", e.getMessage());
            return String.valueOf(obj);
        }
    }
}
